Conversation
yousung1020
commented
Apr 8, 2026
- 실제 서비스 배포용 릴리즈 PR
* infra: CI/CD 파이프라인 초기 구축 완료 * fix: Deploy to EC2 단계에서 오류 발생 내역 수정 후 재테스트 예정 * infra: 테스트 완료 후, develop 브랜치에서 변경이 감지될 경우 Github Actions가 동작하게끔 변경 * refactor: deploy.yml 단순화 * refactor: deploy.yml 단순화 * refactor: deploy.yml 단순화 및 오류 수정 * fix: develop 브랜치에 변경 사항 발생시 자동 재배포 하도록 수정
* feat: Route 및 RouteDetail 엔티티 추가 * feat: [이슈#7] 경로 엔티티 관련 기능 구현 완료 * fit: pr 리뷰 반영
feat: 일정 생성 api 구현
feat: 일정 상세조회 api 구현
refactor:시간대 수정
* feat: RouteDetail 상세 정보 JSON 저장 * feat: 일정 필드 추가
* refactor: ScheduleConverter로 통일 * refactor: 반복 일정 코드 삭제 - 경로일정 Id 음수Id로 변경 - 반복 일정 코드 삭제 - 일반 일정 관리 x -> 불필요한 필드 삭제 * refactor: RouteDetail 저장 방식 변경 (JSON -> 개별 필드) * refactor: 리뷰 반영 수정 * refactor: ScheduleConverter static화 * refactor: 1:1 연관관계 피드백 반영
* feat: 실시간 지하철 도착 정보 조회 기능 구현 * feat: 컨트롤러 구현 * refactor: 리뷰 반영 * fix: deploy.yml에 .env 파일 내용 추가
* feat: 버스 실시간 도착 정보 조회를 위한 출발 정류장 조회 API 구현 * feat: 버스 실시간 도착 정보 조회를 위한 출발 정류장 조회 API 구현
* fix: 실시간 지하철 데이터 필드에서 다음역 이름 정보도 포함하여 응답 * refactor: 리뷰 반영
Feat/#137 upanddown
* feat: 일정 자동 삭제 로직 추가 * 리뷰 반영 수정 * refactor: 벌크 삭제로 변경
* refactor: 대중교통 경로 탐색 시 지하철 상/하행 판별 로직 리팩토링리뷰 반영 * refactor: 리뷰 반영
There was a problem hiding this comment.
Code Review
This pull request initializes the Pace server backend, implementing core features for authentication, member management, scheduling, and transit data integration alongside a Docker-based deployment setup. The review identifies several critical build configuration errors, including non-existent versions for Spring Boot and related libraries, and a significant security vulnerability regarding unauthorized schedule access. Furthermore, the feedback highlights necessary corrections for JPQL bulk delete syntax, potential null pointer exceptions in member processing, and opportunities to improve performance and maintainability through better collection usage and refactoring of hardcoded values.
| @Query("DELETE FROM Route r WHERE r.schedule.endDate < :date") | ||
| void deleteRoutesByScheduleEndDateBefore(@Param("date") LocalDate date); |
There was a problem hiding this comment.
JPQL의 DELETE 문에서는 WHERE 절에서 직접적인 연관관계 경로(e.g., r.schedule.endDate)를 사용할 수 없습니다. 서브쿼리를 사용하여 삭제할 대상을 찾아야 합니다. 이는 성능을 위해 @Modifying과 @Query를 사용하고 자식 엔티티를 먼저 삭제하도록 하는 프로젝트 규칙과도 일치합니다.
| @Query("DELETE FROM Route r WHERE r.schedule.endDate < :date") | |
| void deleteRoutesByScheduleEndDateBefore(@Param("date") LocalDate date); | |
| @Query("DELETE FROM Route r WHERE r.schedule IN (SELECT s FROM Schedule s WHERE s.endDate < :date)") | |
| void deleteRoutesByScheduleEndDateBefore(@Param("date") LocalDate date); |
References
- 성능 향상을 위해 @Modifying과 @query를 사용한 벌크 삭제를 권장하며, 연관관계가 있는 경우 자식 엔티티를 부모보다 먼저 삭제해야 합니다.
| @Query("select s from Schedule s join fetch s.member where s.id in :ids") | ||
| List<Schedule> findAllWithMemberByIdIn(@Param("ids") List<Long> ids, @Param("memberId") Long memberId); |
There was a problem hiding this comment.
이 쿼리는 memberId를 파라미터로 받지만, 실제 쿼리문에서는 사용하지 않고 있습니다. 이로 인해 다른 사용자가 scheduleId만 알면 타인의 일정을 삭제할 수 있는 심각한 보안 취약점이 발생합니다. WHERE 절에 s.member.id = :memberId 조건을 반드시 추가해야 합니다.
| @Query("select s from Schedule s join fetch s.member where s.id in :ids") | |
| List<Schedule> findAllWithMemberByIdIn(@Param("ids") List<Long> ids, @Param("memberId") Long memberId); | |
| @Query("select s from Schedule s join fetch s.member where s.id in :ids and s.member.id = :memberId") | |
| List<Schedule> findAllWithMemberByIdIn(@Param("ids") List<Long> ids, @Param("memberId") Long memberId); |
| testRuntimeOnly 'com.h2database:h2' | ||
|
|
||
| // Swagger UI | ||
| implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:3.0.1") |
| implementation "io.github.openfeign.querydsl:querydsl-jpa:7.0" | ||
| implementation "io.github.openfeign.querydsl:querydsl-core:7.0" | ||
| annotationProcessor "io.github.openfeign.querydsl:querydsl-apt:7.0:jpa" | ||
| annotationProcessor "jakarta.persistence:jakarta.persistence-api" | ||
| annotationProcessor "jakarta.annotation:jakarta.annotation-api" |
There was a problem hiding this comment.
QueryDSL 의존성 정보가 잘못되었습니다. io.github.openfeign.querydsl 그룹의 7.0 버전은 존재하지 않습니다. 공식 QueryDSL 의존성(com.querydsl)을 사용하고 Spring Boot 3.x에 맞는 버전을 사용해야 합니다.
// QueryDSL
implementation 'com.querydsl:querydsl-jpa:5.1.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.1.0:jakarta'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
| @@ -1 +1,6 @@ | |||
| pluginManagement { | |||
| plugins { | |||
| id 'org.jetbrains.kotlin.jvm' version '2.1.21' | |||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.data.jpa.repository.config.EnableJpaAuditing; | ||
| import org.springframework.scheduling.annotation.EnableScheduling; | ||
| import org.springframework.web.reactive.function.client.WebClient; |
| List<String> targetPlaceIdList = targetGroup.getSavedPlaceList().stream() | ||
| .map(SavedPlace::getPlaceId).toList(); |
There was a problem hiding this comment.
targetPlaceIdList를 List 대신 Set으로 만들면 contains 연산의 성능을 O(N)에서 O(1)로 향상시킬 수 있습니다. 이동할 장소의 수가 많아질 경우 성능에 영향을 줄 수 있습니다. targetPlaceIdList.contains를 사용하는 반복문 내부의 성능 개선을 위해 Set으로 변경하는 것을 권장합니다.
| List<String> targetPlaceIdList = targetGroup.getSavedPlaceList().stream() | |
| .map(SavedPlace::getPlaceId).toList(); | |
| java.util.Set<String> targetPlaceIdSet = targetGroup.getSavedPlaceList().stream() | |
| .map(SavedPlace::getPlaceId).collect(java.util.stream.Collectors.toSet()); |
| id 'java' | ||
| id 'org.springframework.boot' version '4.0.1' | ||
| id 'io.spring.dependency-management' version '1.1.7' | ||
| id 'org.jetbrains.kotlin.jvm' |
| String mappedLineName = switch (apiSubwayId) { | ||
| case "1001" -> "1호선"; | ||
| case "1002" -> "2호선"; | ||
| case "1003" -> "3호선"; | ||
| case "1004" -> "4호선"; | ||
| case "1005" -> "5호선"; | ||
| case "1006" -> "6호선"; | ||
| case "1007" -> "7호선"; | ||
| case "1008" -> "8호선"; | ||
| case "1009" -> "9호선"; | ||
| case "1061" -> "중앙선"; | ||
| case "1063" -> "경의중앙선"; | ||
| case "1065" -> "공항철도"; | ||
| case "1067" -> "경춘선"; | ||
| case "1075" -> "수인분당선"; | ||
| case "1077" -> "신분당선"; | ||
| case "1092" -> "우이신설선"; | ||
| case "1093" -> "서해선"; | ||
| case "1081" -> "경강선"; | ||
| case "1032" -> "GTX-A"; | ||
| default -> ""; | ||
| }; | ||
|
|
| # Spring Boot | ||
| pace-app: | ||
| # Docker Hub의 Dockerfile을 기반으로 이미지를 빌드 | ||
| image: shootingstar1020/pace-project:latest |